
#include "Mesh.h"
#include "ply.h"
#include "pfmimage.h"
#include <QMessageBox>


struct PlyVertex
{
    float x, y, z;
    //unsigned char c;
    float c;
    float intensity;
    unsigned char r, g, b, alpha;
    unsigned char m;
};

struct PlyFace
{
    unsigned char nverts;
    int *verts;
};


Mesh::Mesh()
{
    meshMode = new MeshMode();
    minCorner.setX(10000000);
    minCorner.setY(10000000);
    minCorner.setZ(10000000);

    maxCorner.setX(-10000000);
    maxCorner.setY(-10000000);
    maxCorner.setZ(-10000000);



}

Mesh::~Mesh()
{
    delete meshMode;
}

void Mesh::RemoveOccludedVertices(QMatrix4x4 modelViewMat, QMatrix4x4 projMat, QString depthImgFilename)
{
    PFMImage depthImg;
    depthImg.ReadFromFile(depthImgFilename);

//    PFMImage templateImg(256, 256, 3, 0);
    PFMImage depthImgCPU(1024, 1024, 3, 0);

    QVector3D vert;
    QVector4D hVert;
    float un, vn, depth;
    short width = depthImg.GetWidth();
    short height = depthImg.GetHeight();
    short ui, vi;
    for(int i=0; i<vertices.size(); i++)
    {
        vert = vertices[i];
        hVert.setX(vert.x());
        hVert.setY(vert.y());
        hVert.setZ(vert.z());
        hVert.setW(1.0);

        hVert = modelViewMat*hVert;

        depth = hVert.z();


        hVert = projMat * hVert;

        un = hVert.x()/hVert.w();
        vn = hVert.y()/hVert.w();
        un = (un+1)/2.0f;
        vn = (vn+1)/2.0f;
        ui = un*(width-1)+0.5f;
        vi = (1.0f-vn)*(height-1)+0.5f;

        QVector3D pixel;
        pixel.setX(hVert.x());
        pixel.setY(hVert.y());
        pixel.setZ(depth);

        QVector3D pixel1;
        pixel1 = depthImgCPU.GetPixelValue(ui, vi);
        if((abs(pixel1.x()) + abs(pixel1.y()) + abs(pixel1.z()))>0.0)
        {
            if(pixel.z()>pixel1.z())
                depthImgCPU.SetPixelValue(ui, vi, pixel);
        }
        else
        {
            depthImgCPU.SetPixelValue(ui, vi, pixel);
        }

    }

    depthImgCPU.WriteToFile("test.pfm");

    QVector<int> occludedPointIndex;
    QVector<int> oriVertIndex;
    QVector<int> oriVertIndexToNewVertIndex;

    for(int i=0; i<vertices.size(); i++)
    {
        vert = vertices[i];
        hVert.setX(vert.x());
        hVert.setY(vert.y());
        hVert.setZ(vert.z());
        hVert.setW(1.0);

        hVert = modelViewMat*hVert;

        depth = hVert.z();


        hVert = projMat * hVert;

        un = hVert.x()/hVert.w();
        vn = hVert.y()/hVert.w();
        un = (un+1)/2.0f;
        vn = (vn+1)/2.0f;
        ui = un*(width-1)+0.5f;
        vi = (1.0f-vn)*(height-1)+0.5f;


        QVector3D pixel;
        pixel = depthImgCPU.GetPixelValue(ui, vi);
        if(depth < pixel.z())
        {
            occludedPointIndex.append(i);
            oriVertIndex.append(-1);
            oriVertIndexToNewVertIndex.append(-1);
        }
        else
        {
            oriVertIndex.append(i);
            oriVertIndexToNewVertIndex.append(i);
        }

    }
    //remove vertices and colors
    int occludePointsNum = occludedPointIndex.size();

    for(int i=occludePointsNum-1; i>=0; i--)
    {
        int index = occludedPointIndex[i];
        oriVertIndex.remove(index);
        vertices.remove(index);
        vertColors.remove(index);
        vertColorsPtr.remove(index*3, 3);

    }

    for(int i=0; i<oriVertIndex.size(); i++)
    {
        int newIndex = i;
        int oriIndex = oriVertIndex[i];
        oriVertIndexToNewVertIndex[oriIndex] = newIndex;
    }

    //find faces to remove and update vert index
    int oriFaceNum = faces.size()/3;
    QVector<int> deleteFaceIndex;
    for(int i=0; i<oriFaceNum; i++)
    {
       int index1 = faces[i*3];
       int index2 = faces[i*3+1];
       int index3 = faces[i*3+2];
       if(i==26170)
       {
           int b = 0;
       }
       if((oriVertIndexToNewVertIndex[index1]==-1)
        ||(oriVertIndexToNewVertIndex[index2]==-1)
        ||(oriVertIndexToNewVertIndex[index3]==-1))
       {
           deleteFaceIndex.append(i);
           faces[i*3] = -1;
           faces[i*3+1] = -1;
           faces[i*3+2] = -1;
       }
       else
       {
           faces[i*3] = oriVertIndexToNewVertIndex[index1];
           faces[i*3+1] = oriVertIndexToNewVertIndex[index2];
           faces[i*3+2] = oriVertIndexToNewVertIndex[index3];
       }
    }



    //remove deleted faces
    int deletedFaceNum = deleteFaceIndex.size();
    for(int i=deletedFaceNum-1; i>=0; i--)
    {
        int index = deleteFaceIndex[i];
        faces.remove(index*3+2);
        faces.remove(index*3+1);
        faces.remove(index*3);
    }


    //debug
/*    for(int i=0; i<faces.size()/3; i++)
    {
        int index1 = faces[i*3];
        int index2 = faces[i*3+1];
        int index3 = faces[i*3+2];

        if(index1 == -1)
        {
            int a=0;
        }
    }
    */
    //debug

    this->ComputeNormals();


}

void Mesh::Normalize()
{
    QVector3D boxCenter;
    boxCenter.setX((minCorner.x()+maxCorner.x())/2.0f);
    boxCenter.setY((minCorner.y()+maxCorner.y())/2.0f);
    boxCenter.setZ((minCorner.z()+maxCorner.z())/2.0f);

    float maxBoxSize = 0.0f;
    maxBoxSize = maxCorner.x() - minCorner.x();
    maxBoxSize = qMax(maxBoxSize, (maxCorner.y()-minCorner.y()));
    maxBoxSize = qMax(maxBoxSize, (maxCorner.z()-minCorner.z()));

    float avex, avey, avez;
    avex=0;
    avey=0;
    avez=0;
    for(int i=0; i<vertices.size(); i++)
    {
        vertices[i].setX((vertices[i].x()-boxCenter.x())*2/maxBoxSize);
        vertices[i].setY((vertices[i].y()-boxCenter.y())*2/maxBoxSize);
        vertices[i].setZ((vertices[i].z()-boxCenter.z())*2/maxBoxSize);
        avex += vertices[i].x();
        avey += vertices[i].y();
        avez += vertices[i].z();
    }
    avex /= vertices.size();
    avey /= vertices.size();
    avez /= vertices.size();
    aveVertex.setX(avex);
    aveVertex.setY(avey);
    aveVertex.setZ(avez);

    minCorner.setX((minCorner.x()-boxCenter.x())*2/maxBoxSize);
    minCorner.setY((minCorner.y()-boxCenter.y())*2/maxBoxSize);
    minCorner.setZ((minCorner.z()-boxCenter.z())*2/maxBoxSize);

    maxCorner.setX((maxCorner.x()-boxCenter.x())*2/maxBoxSize);
    maxCorner.setY((maxCorner.y()-boxCenter.y())*2/maxBoxSize);
    maxCorner.setZ((maxCorner.z()-boxCenter.z())*2/maxBoxSize);

    //recompute colors for opengl rendering
    vertColorsPtr.resize(vertices.size()*3);
    for(int i=0; i<vertices.size(); i++)
    {
        vertColorsPtr[i*3] = (float)vertColors[i].redF();
        vertColorsPtr[i*3 + 1] = (float)vertColors[i].greenF();
        vertColorsPtr[i*3 + 2] = (float)vertColors[i].blueF();
    }

}

void Mesh::UpdateVerticesDepth(QMatrix4x4 modelViewMat, QMatrix4x4 projMat, QString depthImgFilename)
{
    PFMImage depthImg;
    depthImg.ReadFromFile(depthImgFilename);


    QVector3D vert;
    QVector4D hVert;
    float u, v;
    for(int i=0; i<vertices.size(); i++)
    {
        vert = vertices[i];
        hVert.setX(vert.x());
        hVert.setY(vert.y());
        hVert.setZ(vert.z());
        hVert.setW(1.0);

        hVert = modelViewMat*hVert;
        hVert = projMat * hVert;

        u = hVert.x()/hVert.w();
        v = hVert.y()/hVert.w();
        u = (u+1.0f)/2.0f;
        v = (v+1.0f)/2.0f;
        u = u*(depthImg.GetWidth()-1);
        v = (1.0f-v)*(depthImg.GetHeight()-1);

        int ult = (int)u;
        int vlt = (int)v;
        float w1 = u-ult;
        float w2 = v-vlt;

        QVector3D pixel1 = depthImg.GetPixelValue(ult, vlt);
        QVector3D pixel2 = depthImg.GetPixelValue(ult+1, vlt);
        QVector3D pixel3 = depthImg.GetPixelValue(ult, vlt+1);
        QVector3D pixel4 = depthImg.GetPixelValue(ult+1, vlt+1);
        QVector3D pixel;

        float x1 = pixel1.x()*(1.0f-w1)+pixel2.x()*w1;
        float y1 = pixel1.y()*(1.0f-w1)+pixel2.y()*w1;
        float z1 = pixel1.z()*(1.0f-w1)+pixel2.z()*w1;

        if(!((abs(pixel1.x()) + abs(pixel1.y()) + abs(pixel1.z()))>0.0))
        {
            x1 = pixel2.x();
            y1 = pixel2.y();
            z1 = pixel2.z();
        }

        if(!((abs(pixel2.x()) + abs(pixel2.y()) + abs(pixel2.z()))>0.0))
        {
            x1 = pixel1.x();
            y1 = pixel1.y();
            z1 = pixel1.z();
        }


        float x2 = pixel3.x()*(1.0f-w1)+pixel4.x()*w1;
        float y2 = pixel3.y()*(1.0f-w1)+pixel4.y()*w1;
        float z2 = pixel3.z()*(1.0f-w1)+pixel4.z()*w1;

        if(!((abs(pixel3.x()) + abs(pixel3.y()) + abs(pixel3.z()))>0.0))
        {
            x2 = pixel4.x();
            y2 = pixel4.y();
            z2 = pixel4.z();
        }

        if(!((abs(pixel4.x()) + abs(pixel4.y()) + abs(pixel4.z()))>0.0))
        {
            x2 = pixel3.x();
            y2 = pixel3.y();
            z2 = pixel3.z();
        }


        float x = x1*(1.0f-w2) + x2*w2;
        float y = y1*(1.0f-w2) + y2*w2;
        float z = z1*(1.0f-w2) + z2*w2;


//        if((abs(x) + abs(y) + abs(z))>0.0)
        {
            pixel.setX(x);
            pixel.setY(y);
            pixel.setZ(z);
        }
//        else
//        {
//            pixel.setX(-1);
//            pixel.setY(-1);
//            pixel.setZ(-1);
//        }


        vertices[i].setX(pixel.x());
        vertices[i].setY(pixel.y());
        vertices[i].setZ(pixel.z());

    }

    this->ComputeNormals();
}

void Mesh::Rotate(QMatrix4x4 rotMat)
{
    QVector3D vert;
    QVector4D hVert;
    for(int i=0; i<vertices.size(); i++)
    {
        vert = vertices[i];
        hVert.setX(vert.x());
        hVert.setY(vert.y());
        hVert.setZ(vert.z());
        hVert.setW(1.0);

        hVert = rotMat*hVert;

        vertices[i].setX(hVert.x());
        vertices[i].setY(hVert.y());
        vertices[i].setZ(hVert.z());
    }
}

void Mesh::ComputeNormals()
{
    int faceNum = NumTris();
    int vertNum = NumVerts();
    faceNormals.resize(faceNum);
    vertNormals.resize(vertNum);
    QVector<short> faceNumPerVert;
    faceNumPerVert.resize(vertNum);

    int index1, index2, index3;
    QVector3D vert1, vert2, vert3;
    QVector3D vec13, vec23;
    QVector3D normal;
    for(int i=0; i<faceNum; i++)
    {

        index1 = faces[i*3];
        index2 = faces[i*3+1];
        index3 = faces[i*3+2];

        vert1 = vertices[index1];
        vert2 = vertices[index2];
        vert3 = vertices[index3];

        vec13 = vert1-vert3;
        vec23 = vert2-vert3;

        normal = QVector3D::crossProduct(vec13, vec23);
        normal.normalize();
        faceNormals[i] = normal;
        vertNormals[index1] += normal;
        vertNormals[index2] += normal;
        vertNormals[index3] += normal;
        faceNumPerVert[index1] +=1;
        faceNumPerVert[index2] +=1;
        faceNumPerVert[index3] +=1;

    }

    for(int i=0; i<vertNum; i++)
    {
        vertNormals[i] /= (float)faceNumPerVert[i];
        vertNormals[i].normalize();
    }
}


//template <class floating>
bool Mesh::readPly(const char *filename, const short fileType)
{
    PlyFile *ply = NULL;
    int nelems;
    char **elemNames = NULL;

    FILE *fp=NULL;
    if(fileType == 1)
    {
        fp = fopen(filename, "r");
    }
    else
    {
        fp = fopen(filename, "rb");
    }
    meshMode->_ascii = fileType;
    if (fp)
    {
        ply = ply_read(fp, &nelems, &elemNames);
        if (ply == NULL)
        {
            //cerr << "Mesh::readPly: fail to read " << filename << endl;
            return false;
        }
        meshMode->_ascii = (ply->file_type == PLY_ASCII);
    }
    else
    {
        //cerr << "Mesh::readPly: fail to open " << filename << endl;
        return false;
    }

    // go through each kind of element that we learned is in the file
    // and read them
    char *elemName;
    PlyProperty **plist;
    int numElems, nprops;
    int i, j;
    for (i = 0; i < nelems; i++)
    {
        // get the description of the first element
        elemName = elemNames[i];
        plist = ply_get_element_description(ply, elemName, &numElems, &nprops);

        int xyz = 0;
        int conf = 0;
        int intensity = 0;
        int rgb = 0;
        int mask = 0;
        int vind = 0;
        int alpha = 0;
        for (j = 0; j < nprops; j++)
        {
            plist[j]->internal_type = plist[j]->external_type;

            if (strcmp(plist[j]->name, "x") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, x);
                xyz ++;
            }
            else if (strcmp(plist[j]->name, "y") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, y);
                xyz ++;
            }
            else if (strcmp(plist[j]->name, "z") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, z);
                xyz ++;
            }
            else if (strcmp(plist[j]->name, "confidence") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, c);
                conf ++;
            }
            else if(strcmp(plist[j]->name, "intensity") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, intensity);
                intensity ++;

            }
            else if ((strcmp(plist[j]->name, "diffuse_red") == 0) || (strcmp(plist[j]->name, "red") == 0))
            {
                plist[j]->offset = offsetof(PlyVertex, r);
                rgb ++;
            }
            else if ((strcmp(plist[j]->name, "diffuse_green") == 0) || strcmp(plist[j]->name, "green") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, g);
                rgb ++;
            }
            else if ((strcmp(plist[j]->name, "diffuse_blue") == 0) || strcmp(plist[j]->name, "blue") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, b);
                rgb ++;
            }
            else if(strcmp(plist[j]->name, "alpha") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, alpha);
                alpha++;
            }
            else if (strcmp(plist[j]->name, "mask") == 0)
            {
                plist[j]->offset = offsetof(PlyVertex, m);
                mask ++;
            }

            if (strcmp(plist[j]->name, "vertex_indices") == 0)
            {
                plist[j]->offset = offsetof(PlyFace, verts);
                plist[j]->count_external = plist[j]->count_internal = PLY_UCHAR;
                plist[j]->count_offset = offsetof(PlyFace, nverts);
                vind ++;
            }
            else
            {
                plist[j]->count_external = plist[j]->count_internal = 0;
                plist[j]->count_offset = 0;
            }

            if (ply_get_property(ply, elemName, plist[j]) == 0)
            {
 //               cerr << "Mesh::readPly: fail to read " << plist[j]->name << " in " << filename << endl;
                return false;
            }

            free(plist[j]->name);
            free(plist[j]);
        }
        free(plist);

        // if we're on vertex elements, read them in
        if (strcmp("vertex", elemName) == 0)
        {
            if (xyz != 3)
            {
 //               cerr << "Mesh::readPly: fail to read xyz in " << filename << endl;
                return false;
            }

            if (meshMode->_hasConf == -1)
            {
                meshMode->_hasConf = (conf == 1);
            }
            else if (meshMode->_hasConf == 1 &&	conf != 1)
            {
                 //cerr << "Mesh::readPly: fail to read confidence in " << filename << endl;
                return false;
            }

            if (meshMode->_hasColor == -1)
            {
                meshMode->_hasColor = (rgb == 3);
            }
            else if (meshMode->_hasColor ==1 && rgb != 3)
            {
                //cerr << "Mesh::readPly: fail to read rgb in " << filename << endl;
                return false;
            }

            if (meshMode->_hasMask == -1)
            {
                meshMode->_hasMask = (mask == 1);
            }
            else if (meshMode->_hasMask == 1 && mask != 1)
            {
                //cerr << "Mesh::readPly: fail to read mask in " << filename << endl;
                return false;
            }

            if(meshMode->_hasAlpha == -1)
            {
                meshMode->_hasAlpha = (alpha==1);
            }
            else if(meshMode->_hasAlpha==1 && alpha!= 1)
            {
                return false;
            }

            vertices.resize(numElems);
            if(meshMode->_hasColor)
            {
                vertColors.resize(numElems);
            }
            // grab all the vertex elements
            for (j = 0; j < numElems; j++)
            {
                // grab an element from the file
                PlyVertex vert;
                ply_get_element (ply, &vert);

                //Vertex <floating> &mv = _verts[j];
                //mv._coord[0] = (floating)vert.x;
                //mv._coord[1] = (floating)vert.y;
                //mv._coord[2] = (floating)vert.z;

                vertices[j].setX(vert.x);
                vertices[j].setY(vert.y);
                vertices[j].setZ(vert.z);

                //compute the bounding box
                if(vert.x < minCorner.x())
                    minCorner.setX(vert.x);
                if(vert.y < minCorner.y())
                    minCorner.setY(vert.y);
                if(vert.z < minCorner.z())
                    minCorner.setZ(vert.z);

                if(vert.x > maxCorner.x())
                    maxCorner.setX(vert.x);
                if(vert.y > maxCorner.y())
                    maxCorner.setY(vert.y);
                if(vert.z > maxCorner.z())
                    maxCorner.setZ(vert.z);


                if (meshMode->_hasConf)
                {
                    float c = vert.c; //mv._confidence = vert.c;
                }
                if (meshMode->_hasColor)
                {
                    //mv._matDiff[0] = vert.r;
                    //mv._matDiff[1] = vert.g;
                    //mv._matDiff[2] = vert.b;
                    vertColors[j].setRed(vert.r);
                    vertColors[j].setGreen(vert.g);
                    vertColors[j].setBlue(vert.b);

                }
                if (meshMode->_hasMask)
                {
                    unsigned char mask = vert.m;
                }
            }
        }
        // if we're on face elements, read them in
        else if (strcmp("face", elemName) == 0)
        {
            if (vind != 1)
            {
                //cerr << "Mesh::readPly: fail to read vertex_indices in " << filename << endl;
                return false;
            }
            if (meshMode->_hasTris == 0)
            {
                continue;
            }
            else if (meshMode->_hasTris == -1)
            {
                meshMode->_hasTris = 1;
            }

           // _tris.resize(numElems);
            faces.resize(numElems*3);
            // grab all the face elements
            for (j = 0; j < numElems; j++)
            {
                // grab an element from the file
                PlyFace face;
                ply_get_element(ply, &face);

                //Triangle <floating> &mt = _tris[j];
                //mt._vindex1 = face.verts[0];
                //mt._vindex2 = face.verts[1];
                //mt._vindex3 = face.verts[2];

                faces[j*3] = face.verts[0];
                faces[j*3 + 1] = face.verts[1];
                faces[j*3 + 2] = face.verts[2];

                free(face.verts);
            }
        }

        free(elemName);
    }
    free(elemNames);

    ply_close(ply);

    _name = filename;
    return true;
}

//template <class floating>
//bool Mesh<floating>::writePly(const char *filename, const MeshMode *meshMode) const
//{
/*    PlyFile *ply;
    FILE *fp = fopen(filename, "wb");
    if (fp)
    {
        char *elem_names[] = { // list of the kinds of elements in the user's object
            "vertex", "face"
        };
        ply = ply_write (fp,
            meshMode->_hasTris ? 2 : 1,
            elem_names,
            meshMode->_ascii ? PLY_ASCII : PLY_BINARY_LE);
    }
    else
    {
        cerr << "Mesh::writePly: fail to open " << filename << endl;
        return false;
    }

    PlyProperty vert_props[8] = { // list of property information for a vertex
        {"x", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,x), 0, 0, 0, 0},
        {"y", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,y), 0, 0, 0, 0},
        {"z", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,z), 0, 0, 0, 0},
        //whether to write the following prop depends on meshMode
        //{"confidence", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,c), 0, 0, 0, 0},
        //{"diffuse_red", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,r), 0, 0, 0, 0},
        //{"diffuse_green", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,g), 0, 0, 0, 0},
        //{"diffuse_blue", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,b), 0, 0, 0, 0},
        //{"mask", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,m), 0, 0, 0, 0},
    };
    int nprops = 3;

    // describe what properties go into the vertex elements
    if (meshMode->_hasConf)
    {
        PlyProperty *p = vert_props + nprops;
        p->name = "confidence";
        p->external_type = p->internal_type = PLY_FLOAT;
        p->offset = offsetof(PlyVertex,c);
        p->is_list = p->count_external = p->count_internal = p->count_offset = 0;
        nprops ++;
    }
    if (meshMode->_hasColor)
    {
        PlyProperty *p;

        p = vert_props + nprops;
        p->name = "diffuse_red";
        p->external_type = p->internal_type = PLY_UCHAR;
        p->offset = offsetof(PlyVertex,r);
        p->is_list = p->count_external = p->count_internal = p->count_offset = 0;
        nprops ++;

        p = vert_props + nprops;
        p->name = "diffuse_green";
        p->external_type = p->internal_type = PLY_UCHAR;
        p->offset = offsetof(PlyVertex,g);
        p->is_list = p->count_external = p->count_internal = p->count_offset = 0;
        nprops ++;

        p = vert_props + nprops;
        p->name = "diffuse_blue";
        p->external_type = p->internal_type = PLY_UCHAR;
        p->offset = offsetof(PlyVertex,b);
        p->is_list = p->count_external = p->count_internal = p->count_offset = 0;
        nprops ++;
    }
    if (meshMode->_hasMask)
    {
        PlyProperty *p = vert_props + nprops;
        p->name = "mask";
        p->external_type = p->internal_type = PLY_UCHAR;
        p->offset = offsetof(PlyVertex,m);
        p->is_list = p->count_external = p->count_internal = p->count_offset = 0;
        nprops ++;
    }

    ply_describe_element(ply, "vertex", (int)_verts.size(), nprops, vert_props);

    if (meshMode->_hasTris)
    {
        PlyProperty face_props[] = { // list of property information for a face
            {"vertex_indices", PLY_INT, PLY_INT, offsetof(PlyFace,verts),
                1, PLY_UCHAR, PLY_UCHAR, offsetof(PlyFace,nverts)},
        };

        ply_describe_element(ply, "face", (int)_tris.size(), 1, face_props);
    }

    ply_header_complete(ply);

    int i;

    // set up and write the vertex elements
    ply_put_element_setup(ply, "vertex");
    PlyVertex pv;
    for (i = 0; i < (int)_verts.size(); i++)
    {
        const Vertex <floating> &mv = _verts[i];

        pv.x = (float)mv._coord[0];
        pv.y = (float)mv._coord[1];
        pv.z = (float)mv._coord[2];
        if (meshMode->_hasConf)
        {
            pv.c = mv._confidence;
        }
        if (meshMode->_hasColor)
        {
            pv.r = mv._matDiff[0];
            pv.g = mv._matDiff[1];
            pv.b = mv._matDiff[2];
        }
        if (meshMode->_hasMask)
        {
            pv.m = mv._mask;
        }
        ply_put_element(ply, (void *)&pv);
    }

    if (meshMode->_hasTris)
    {
        // set up and write the face elements
        ply_put_element_setup (ply, "face");
        PlyFace pf;
        int vindex[3];
        pf.nverts = 3;
        pf.verts = vindex;
        for (i = 0; i < (int)_tris.size(); i++)
        {
            const Triangle <floating> &mt = _tris[i];
            pf.verts[0] = mt._vindex1;
            pf.verts[1] = mt._vindex2;
            pf.verts[2] = mt._vindex3;
            ply_put_element(ply, (void *) &pf);
        }
    }

    //close file, free memory pointed by ply
    ply_close(ply);
*/
//    return true;
//}


